<?php
namespace Plu\Library\Services\Platform\Media;

use Plu\Library\Services\ServiceBase,
    Plu\Library\Services\Platform\Game\GamesService,
    Plu\Library\Services\Redis\Media\MediaRedis,
    Plu\Library\Services\Utility\NumberService,

    Plu\Library\Models\Platform\Media\Media as MediaModel,
    Plu\Library\Models\Platform\Rooms\Room  as RoomModel,
    Plu\Library\Models\Platform\Tag\Tags as TagsModel,
    Plu\Library\Models\Platform\Album\Album as AlbumModel,
    Plu\Library\Models\Platform\Album\AlbumOfMedia as AlbumOfMediaModel,

    Phalcon\Db\Column;

/**
 * 专用视频查询接口 
 */

class MediaService extends ServiceBase {
    const VIDEO_CACHE_TIME = 3600;

    /**
     * 获取指定房间的视频
     */
    private $roomIds = [];

    /**
     * 屏蔽指定房间的视频
     */
    private $exroomIds = [];

    /**
     * 获取指定的视频id
     */
    private $mediaIds = [];

    /**
     * 屏蔽指定的视频id
     */
    private $exmediaIds = [];

    /**
     * 获取指定的游戏id视频
     */
    private $gameIds = [];

    /**
     * 屏蔽指定游戏的id
     */
    private $exgameIds = [];

    /**
     * 查询指定的uid房间
     */
    private $uids = [];

    /**
     * 排除指定的uid房间
     */
    private $exuids = [];


    /**
     * 设定mediaTags
     */
    private $tags = [];

    /**
     * 标签是否使用严格匹配模式
     */
    private $strictMode = true;

    /**
     * 设定排序模式
     */
    private $sortby = 'top';

    /**
     * 是否需要获取删除的
     */
    private $hasDelete = false;

    /**
     * 获取指定时间范围的
     */
    private $createAfter = "";

    /**
     * 设定视频来源
     */
    private $source = 0;

    /**
     * 设定视频的时长
     */
    private $duration = 0;

    /**
     * 视频审核状态
     */
    private $examine = 4;

    /**
     * 视频是否需要格式化数据
     */
    private $formatted = true;



    private $mediaRedis;

    public function __construct() {
        $this->mediaRedis = new MediaRedis;
    }

    public function reset() {
        $this->roomIds = [];
        $this->exroomIds = [];
        $this->mediaIds = [];
        $this->exmediaIds = [];
        $this->gameIds = [];
        $this->exgameIds = [];
        $this->uids                  = [];
        $this->exuids                = [];
        $this->tags = [];
        $this->strictMode = true;
        $this->sortby = 'top';
        $this->hasDelete = false;
        $this->createAfter = "";
        $this->source = 0;
        $this->duration = 0;
        $this->examine = 4;
        $this->formatted = true;

        return $this;
    }

    /**
     * 计算guid
     */
    private function getGuid($params = array()) {
        $p = array(
            $this->roomIds,
            $this->exroomIds,
            $this->mediaIds,
            $this->exmediaIds,
            $this->gameIds,
            $this->exgameIds,
            $this->uids,
            $this->exuids,
            $this->tags,
            $this->strictMode,
            $this->sortby,
            $this->hasDelete,
            $this->createAfter,
            $this->source,
            $this->duration,
            $this->examine,
            $this->formatted
        );

        $p = array_merge($p, $params);

        return md5(serialize($p));
    }

    /**
     * 设定需要筛选的房间id
     */
    public function setRoomIds($roomIds) {
        if (!is_array($roomIds)) {
            $roomIds = array($roomIds);
        }

        $roomIds = NumberService::toNumberList($roomIds);

        $roomIds = array_values(array_unique(array_merge($roomIds, $this->roomIds)));

        $this->roomIds = $roomIds;

        return $this;
    }

    /**
     * 设定需要排除的房间id
     */
    public function setExroomIds($roomIds) {
        if (!is_array($roomIds)) {
            $roomIds = array($roomIds);
        }

        $roomIds = NumberService::toNumberList($roomIds);

        $roomIds = array_values(array_unique(array_merge($roomIds, $this->exroomIds)));

        $this->exroomIds = $roomIds;

        return $this;
    }

    /**
     * 设定需要的uid
     */
    public function setUids($uids) {
        if (!is_array($uids)) {
            $uids = array($uids);
        }

        $this->uids = $uids;

        $roomIds = $this->roomRedis->getRoomIdsByUids($uids);
        $roomIds = array_values($roomIds);
        $roomIds = NumberService::toNumberList($roomIds);

        $this->setRoomIds($roomIds);

        return $this;
    }

    public function setExuids($uids) {
        if (!is_array($uids)) {
            $uids = array($uids);
        }

        $this->uids = $uids;

        $roomIds = $this->roomRedis->getRoomIdsByUids($uids);
        $roomIds = array_values($roomIds);
        $roomIds = NumberService::toNumberList($roomIds);

        $this->setExroomIds($roomIds);

        return $this;
    }


    /**
     * 设定需要获取的视频id
     */
    public function setMediaIds($mediaIds) {
        if (!is_array($mediaIds)) {
            $mediaIds = array($mediaIds);
        }

        $mediaIds = NumberService::toNumberList($mediaIds);

        $mediaIds = array_values(array_unique(array_merge($mediaIds, $this->mediaIds)));

        $this->mediaIds = $mediaIds;

        return $this;
    }

    /**
     * 获取需要排除的视频id
     */
    public function setExmediaIds($mediaIds) {
        if (!is_array($mediaIds)) {
            $mediaIds = array($mediaIds);
        }

        $mediaIds = NumberService::toNumberList($mediaIds);

        $mediaIds = array_values(array_unique(array_merge($mediaIds, $this->exmediaIds)));

        $this->exmediaIds = $mediaIds;

        return $this;
    }

    /**
     * 设定需要筛选的游戏id
     */
    public function setGames($ids, $isIncludeChildrens = false) {
        if (!is_array($ids)) {
            $ids = array($ids);
        }
        $games = NumberService::toNumberList($ids);

        if ($isIncludeChildrens) {
            $len = count($games);
            for ($c = 0; $c < $len; $c++) {
                $gameid = $games[$c];
                $game = GamesService::getGameInfoById($gameid);
                if (!empty($game['subgames'])) {
                    $games = array_merge($games, $game['subgames']);
                }
            }

            $games = array_values(array_unique($games));
        }

        $this->gameIds = $games;
        return $this;
    }

    /**
     * 设定需要排除的游戏id
     */
    public function setExgames($ids, $isIncludeChildrens = false) {
        if (!is_array($ids)) {
            $ids = array($ids);
        }
        $games = NumberService::toNumberList($ids);

        if ($isIncludeChildrens) {
            $len = count($games);
            for ($c = 0; $c < $len; $c++) {
                $gameid = $games[$c];
                $game = GamesService::getGameInfoById($gameid);
                if (!empty($game['subgames'])) {
                    $games = array_merge($games, $game['subgames']);
                }
            }

            $games = array_values(array_unique($games));
        }

        $this->exgameIds = $games;

        return $this;
    }

    /**
     * 设定需要筛选的 tags
     */
    public function setTags($tags) {
        $tags = TagsModel::getTagsId($tags);
        $tags = NumberService::toNumberList($tags);

        $this->tags = $tags;

        return $this;
    }

    /**
     * 设定排序逻辑
     */
    public function setSortby($sortby = 'top') {
        if (!in_array($sortby, MediaModel::SortTypes)) {
            $sortby = "top";
        }

        $this->sortby = $sortby;

        return $this;
    }

    /**
     * 设定标签是否需要严格模式， 严格模式为AND，否则为OR
     */
    public function setStrictMode($strict = true) {
        $this->strictMode = (bool)$strict;

        return $this;
    }

    /**
     * 设定是否同时需要显示已删除的视频
     */
    public function setDeletable($deletion = false) {
        $this->hasDelete = (bool)$deletion;

        return $this;
    }

    /**
     * 显示此创建时间之后的数据
     */
    public function setCreateAfter($create_after = '') {
        $this->createAfter = $create_after;

        return $this;
    }

    /**
     * 设定视频的显示来源
     */
    public function setSource($source = 0) {
        $source = intval($source);
        if ($source > 0) {
            $this->source = $source;
        }

        return $this;
    }

    /**
     * 设定视频时长
     */
    public function setDuration($duration = 0) {
        $duration = intval($duration);

        $this->duration = $duration;

        return $this;
    }

    /**
     * 设定返回的数据是否需要格式化？
     */
    public function setFormatted($format = true) {
        $this->formatted = (bool)$format;

        return $this;
    }

    public function setExamineStatus($examine = 4) {
        $examine = intval($examine);
        $this->examine = $examine;

        return $this;
    }

    /**
     * 根据RoomId查询视频
     * @param roomIds 房间Id
     * @param excludes 需要排序的房间ID
     * @param start_index 起始点
     * @param $max_results 最多显示数量
     * @param $sort_by 排序
     * @param $create_after 晚于创建时间
     * @param $source 视频来源
     */
    public function getVideosOfRooms($roomIds = array(), $excludes = array(), $mediaIds = array(), $excludeMediaIds = array(), $start_index = 0, $max_results = 50, $sort_by = 'top', $create_after = "", $source = 0) {

        $this->reset()
             ->setRoomIds($roomIds)
             ->setExroomIds($excludes)
             ->setMediaIds($mediaIds)
             ->setExmediaIds($excludeMediaIds)
             ->setSortby($sort_by)
             ->setSource($source)
             ->setCreateAfter($create_after);

        return $this->_getVideos($start_index, $max_results);
    }

    /**
     * 根据多个游戏获取视频
     * @param gameIds 游戏ID
     * @param excludes 需要排除的gameid
     * @param mediaId 包含的视频id
     * @param $excludeMediaIds 不包含的视频id
     * @param start_index 起始点
     * @param $max_results 最多显示数量
     * @param $sort_by 排序
     * @param $create_after 晚于创建时间
     * @param $source 视频来源
     */
    public function getVideosOfGames($gameIds = array(), $excludes = array(), $mediaIds = array(), $excludeMediaIds = array(), $start_index = 0, $max_results = 50, $sort_by = 'top', $create_after = "-365 days", $source = 0) {

        $this->reset()
             ->setGames($gameIds)
             ->setExgames($excludes)
             ->setMediaIds($mediaIds)
             ->setExmediaIds($excludeMediaIds)
             ->setSortby($sort_by)
             ->setSource($source)
             ->setCreateAfter($create_after);

        return $this->_getVideos($start_index, $max_results);
    }

    public function getVideosByTags($tags, $strict = true, $roomIds = array(), $gameIds = array(), $start_index = 0, $max_results = 50, $sort_by = 'top', $create_after = "") {

        $this->reset()
             ->setTags($tags)
             ->setStrictMode($strict)
             ->setRoomIds($roomIds)
             ->setGames($gameIds)
             ->setSortby($sort_by)
             ->setCreateAfter($create_after);

        return $this->_getVideos($start_index, $max_results);
    }


    public function getVideos($roomIds = array(), $excludeRoomIds = array(), $gameIds = array(), $excludeGameIds = array(), $mediaIds = array(), $excludeMediaIds = array(), $start_index = 0, $max_results = 50, $sort_by = 'top', $create_after = "-365 days", $source = 0, $hasDelete = false, $duration = 0) {

        $this->reset()
             ->setRoomIds($roomIds)
             ->setExroomIds($excludeRoomIds)
             ->setGames($gameIds)
             ->setExgames($excludeGameIds)
             ->setMediaIds($mediaIds)
             ->setExmediaIds($excludeMediaIds)
             ->setSortby($sort_by)
             ->setCreateAfter($create_after)
             ->setSource($source)
             ->setDeletable($hasDelete)
             ->setDuration($duration);

        return $this->_getVideos($start_index, $max_results);
    }

    /**
     * 新增方法，用户暴露_getVideos方法
     */
    public function getItems($start_index = 0, $max_results = 50, $cacheTime = null) {

        return $this->_getVideos($start_index, $max_results, $cacheTime);

    }

    /**
     * 内部获取视频接口，getVideosOfGames 和 getVideosOfRoomIds 都从接口获取数据
     */
    private function _getVideos($start_index = 0, $max_results = 50, $cacheTime = null) {
        if (is_null($cacheTime)) {
            $cacheTime = self::VIDEO_CACHE_TIME;
        }

        $cacheHandler = $this->getCacheHandler();
        $now = time();
        if ($cacheTime > 0) {
            $hash = $this->getGuid(func_get_args());
            $guid = sprintf("tgavideos_%s", $hash);
            list($videos, $exptime) = $cacheHandler->get($guid, $cacheTime);

            if (is_numeric($exptime) && (($now - $exptime) >= $cacheTime)) {
                $videos = array();//reset
            }
        } else {
            $videos = array();
        }

        if (!empty($videos) && is_array($videos)) {
            return $videos;
        }

        if ($start_index <= 0) {
            $start_index = 0;
        }

        $max_results = $max_results == 0 ? 10 : $max_results;
        if ($max_results > 50) {
            $max_results = 50;
        }

        $mediaModel = new MediaModel;

        list($totalCount, $items) = $mediaModel->getVideos($this->roomIds, $this->exroomIds, $this->gameIds, $this->exgameIds, $this->mediaIds, $this->exmediaIds, $this->tags, $this->strictMode, $start_index, $max_results, $this->sortby, $this->createAfter, $this->source, $this->hasDelete, $this->duration, $this->examine);

        $data = array();
        if ($this->formatted) {
            array_walk($items, function($video) use (&$data) {
                $item = $this->formatVideo($video);
                $data[] = $item;
            });
        } else {
            $data = $items;
        }

        $videos = array($totalCount, $data);

        if ($cacheTime > 0) {
            $cacheHandler->save($guid, array($videos, $now), $cacheTime);
        }

        return $videos;
    }

    private function formatVideo($video, $load_today_data = true) {
        $item = array();

        //视频ID
        $id = $video['MediaId'];

        //get roomInfo
        $roomId = $video['RoomId'];
        $roomInfo = RoomModel::getRoomInfo($roomId);

        //get game info
        $gameId = $video['GameId'];
        $gameInfo = GamesService::getGameInfoById($gameId);

        $createtime = strtotime($video['CreateTime']);

        //图片
        $images = array(
            'thumb'    => $video['Cover'],
            'cover'    => $video['Cover'],
            'original' => $video['Cover']
        );

        //parse FlashURL
        $flashURL = $video['FlashUrl'];
        if (preg_match('/^http.*?\qq\.com/', $flashURL)) { //QQ
            $query_string = parse_url($flashURL);
            parse_str($query_string['query'], $queries);
            if ($queries['vid']) {
                $vid = explode("|", $queries['vid']);
                $vid = array_shift($vid);

                $images['normal'] = "http://shp.qpic.cn/qqvideo_ori/0/{$vid}_360_204/0";
                $images['original'] = "http://shp.qpic.cn/qqvideo/0/{$vid}/0";
            }
        } elseif (preg_match('/^http.*?\ykimg\.com/', $video['Cover'])) { //YOUKU
            $url = parse_url($video['Cover']);
            list(,$imgurl) = explode('/', $url['path']);
            $images['normal'] =	$url['scheme'].'://'. $url['host'] . '/1' . substr($imgurl, 1);
            $images['original'] = $url['scheme'].'://'. $url['host'] . '/2' . substr($imgurl, 1);

            //unset($images['cover']);
        }

        $views = $video['TotalViews'];
        $recentViews = $video['RecentViews'];
        if ($load_today_data) {
            $pvcount = $this->mediaRedis->getVideoPVCount($roomId, $id);
            $views = $views + intval($pvcount);
        }

        $item = array(
            'id'           => intval($id),
            'views'        => intval($views),
            'recentviews'  => intval($recentViews),
            'comments'     => intval($video['TotalComments']),
            'game'         => $gameInfo,
            'url'          => sprintf('%s/v/%d', $video['Domain'], $id),
            'channel'      => array(
                'name'     => $roomInfo['Name'],
                'avatar'   => $roomInfo['Logo'],
                'domain'   => $roomInfo['Domain'],
                'id'       => intval($roomInfo['RoomId']),
                'verified' => $roomInfo['VerifiedInformation']
            ),
            'createtime'       => $createtime * 1000,
            'duration'         => intval($video['TimeSpan']),
            'description'      => $video['Desc'],
            'title'            => $video['Title'],
            'images'           => $images,
            'score'            => array(
                'overall'      => $video['OverallScore'],
                'master_total' => $video['MasterTotalScore'],
                'master'       => $video['MasterScore'],
                'fun_total'    => $video['FunTotalScore'],
                'fun'          => $video['FunScore'],
                'teach_total'  => $video['TeachTotalScore'],
                'teach'        => $video['TeachScore'],
                'count'        => intval($video['ScoreCount']),
                'type'         => intval($video['ScoreType'])
            ),
            'quality' => intval($video['Definition'])
        );

        return $item;
    }

    /**
     * 根据视频ID获取视频信息
     * @param $ids 需要查询的字段
     * @param $extra 需要扩展加入的数据, 结构是  key => array( vid => value )
     */
    public function getVideoInfo($ids, $extraValues = array()) {
        $items = array();

        $ids = NumberService::toNumberList($ids);
        if ( count($ids) == 0 ) {
            return $items;
        }

        $videos = MediaModel::getVideosByIds($ids);

        if (count($videos) == 0) {
            return $items;
        }

        array_walk($ids, function($id) use ($videos, &$items) {
            $video = $videos[$id];
            if (!empty($video)) {
                $item = $this->formatVideo($video);
                $items[$id] = $item;
            }
        });

        if (!empty($extraValues)) {
            foreach ($extraValues as $k => $d) {
                foreach ($d as $vid => $val) {
                    if ($items[$vid]) {
                        $items[$vid][$k] = $val;
                    }
                }
            }
        }

        $items = array_values($items);

        return $items;
    }

    /**
     * 通过专辑id获取视频
     * @param int $aid 专辑id
     * @return array $result 专辑视频
     */
    public function getVideosByAlbumId($aid) {
        $albumOfMediaInfo = AlbumOfMediaModel::find(array(
            'AlbumId = :albumId:',
            'bind' => array(
                'albumId' => $aid,
            ),
            'bindTypes' => array(
                'albumId' => Column::BIND_PARAM_INT,
            )
        ));

        $videosInfo = array();
        foreach($albumOfMediaInfo as $item) {
            $videosInfo[$item->MediaId] = $this->getVideoInfo(array($item->MediaId));
        }	    

        return $videosInfo;
    }

    /**
     * 获取专辑信息
     * @param int $aid 专辑id
     * @return object $albumInfo
     */
    public function getAlbumById($aid) {
        $albumInfo = AlbumModel::findFirst(array(
            'Id = :aid:',
            'bind' => array(
                'aid' => $aid,
            ),
            'bindTypes' => array(
                'aid' => Column::BIND_PARAM_INT,
            )
        ));

        return $albumInfo;
    }
}

?>
